package com.edu.exam.entity.academic;

import com.edu.exam.enums.academic.AcademicYearStatus;
import com.edu.exam.enums.academic.SemesterType;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.*;

import java.time.LocalDate;
import java.time.LocalDateTime;

/**
 * 学期实体类
 * 所属模块：F-07 基础数据管理模块
 * 对应数据库表：semesters
 *
 * 管理学校学期的详细信息，包含学期的时间安排、各阶段的起止时间。
 * 支持学期状态的判断和时间段验证。
 *
 * @author System
 * @version 1.0.0
 */
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "semesters")
@Comment("学期表")
public class Semester {

    /**
     * 主键ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    /**
     * 学期代码，唯一标识符
     */
    @NotBlank(message = "学期代码不能为空")
    @Size(max = 50, message = "学期代码长度不能超过50个字符")
    @Column(name = "semester_code", nullable = false, unique = true, length = 50)
    private String semesterCode;

    /**
     * 学期名称
     */
    @NotBlank(message = "学期名称不能为空")
    @Size(max = 100, message = "学期名称长度不能超过100个字符")
    @Column(name = "semester_name", nullable = false, length = 100)
    private String semesterName;

    /**
     * 学年
     */
    @NotBlank(message = "学年不能为空")
    @Size(max = 20, message = "学年长度不能超过20个字符")
    @Column(name = "academic_year", nullable = false, length = 20)
    private String academicYear;

    /**
     * 学期类型
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "semester_type", length = 20)
    private SemesterType semesterType;

    /**
     * 开始日期
     */
    @NotNull(message = "开始日期不能为空")
    @Column(name = "start_date", nullable = false)
    private LocalDate startDate;

    /**
     * 结束日期
     */
    @NotNull(message = "结束日期不能为空")
    @Column(name = "end_date", nullable = false)
    private LocalDate endDate;

    /**
     * 注册开始日期
     */
    @Column(name = "registration_start_date")
    private LocalDate registrationStartDate;

    /**
     * 注册结束日期
     */
    @Column(name = "registration_end_date")
    private LocalDate registrationEndDate;

    /**
     * 教学开始日期
     */
    @Column(name = "teaching_start_date")
    private LocalDate teachingStartDate;

    /**
     * 教学结束日期
     */
    @Column(name = "teaching_end_date")
    private LocalDate teachingEndDate;

    /**
     * 考试开始日期
     */
    @Column(name = "exam_start_date")
    private LocalDate examStartDate;

    /**
     * 考试结束日期
     */
    @Column(name = "exam_end_date")
    private LocalDate examEndDate;

    /**
     * 当前学期标识
     */
    @Column(name = "is_current")
    private Boolean isCurrent;

    /**
     * 最大课程数
     */
    @Column(name = "max_courses")
    private Integer maxCourses;

    /**
     * 最大学分
     */
    @Column(name = "max_credits", precision = 4, scale = 1)
    private Double maxCredits;

    /**
     * 是否允许退课
     */
    @Column(name = "allow_drop")
    private Boolean allowDrop;

    /**
     * 是否允许选课
     */
    @Column(name = "allow_registration")
    private Boolean allowRegistration;

    /**
     * 状态
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false, length = 20)
    @Builder.Default
    private AcademicYearStatus status = AcademicYearStatus.PLANNING;

    /**
     * 备注
     */
    @Size(max = 1000, message = "备注长度不能超过1000个字符")
    @Column(name = "remarks", length = 1000)
    private String remarks;

    /**
     * 创建时间
     */
    @Column(name = "created_time", nullable = false, updatable = false)
    private LocalDateTime createdTime;

    /**
     * 更新时间
     */
    @Column(name = "updated_time", nullable = false)
    private LocalDateTime updatedTime;

    /**
     * 创建人
     */
    @Size(max = 50, message = "创建人长度不能超过50个字符")
    @Column(name = "created_by", nullable = false, length = 50)
    private String createdBy;

    /**
     * 更新人
     */
    @Size(max = 50, message = "更新人长度不能超过50个字符")
    @Column(name = "updated_by", length = 50)
    private String updatedBy;

    @PrePersist
    protected void onCreate() {
        LocalDateTime now = LocalDateTime.now();
        this.createdTime = now;
        this.updatedTime = now;
    }

    @PreUpdate
    protected void onUpdate() {
        this.updatedTime = LocalDateTime.now();
    }

    /**
     * 获取学期时长（天数）
     */
    public long getDurationDays() {
        if (startDate == null || endDate == null) {
            return 0;
        }
        return startDate.until(endDate).getDays() + 1;
    }

    /**
     * 获取选课时长（天数）
     */
    public long getRegistrationDurationDays() {
        if (registrationStartDate == null || registrationEndDate == null) {
            return 0;
        }
        return registrationStartDate.until(registrationEndDate).getDays() + 1;
    }

    /**
     * 判断注册期是否开放
     */
    public boolean isRegistrationOpen() {
        LocalDate now = LocalDate.now();
        return registrationStartDate != null && registrationEndDate != null
                && !now.isBefore(registrationStartDate) && !now.isAfter(registrationEndDate);
    }

    /**
     * 判断是否在教学期
     */
    public boolean isTeachingPeriod() {
        LocalDate now = LocalDate.now();
        return teachingStartDate != null && teachingEndDate != null
                && !now.isBefore(teachingStartDate) && !now.isAfter(teachingEndDate);
    }

    /**
     * 判断是否在考试期
     */
    public boolean isExamPeriod() {
        LocalDate now = LocalDate.now();
        return examStartDate != null && examEndDate != null
                && !now.isBefore(examStartDate) && !now.isAfter(examEndDate);
    }

    /**
     * 获取周数
     */
    public int getWeekCount() {
        if (startDate == null || endDate == null) {
            return 0;
        }
        return (int) ((endDate.toEpochDay() - startDate.toEpochDay()) / 7) + 1;
    }
}